/*
  阿里云 长文本语音合成（SpeechLongSynthesizer）WebSocket 字幕获取模块
  - 连接网关: wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1
  - 开启 enable_subtitle，实时接收 MetaInfo 的 subtitles
  - 聚合为 TimestampData[] 返回

  说明：阿里云不同线路与版本的具体帧格式可能略有差异。本模块采用通用格式：
  发送：{"header":{"namespace":"SpeechLongSynthesizer","name":"StartTask","appkey":"...","token":"..."},"payload":{...}}
  结束：{"header":{"namespace":"SpeechLongSynthesizer","name":"StopTask"}}
  接收：MetaInfo/Completed/Fail
*/

export interface TimestampData {
  text: string
  start: number
  end: number
  phoneme?: string
}

export interface WsSubtitleItem {
  text: string
  begin_time: number
  end_time: number
  sentence: boolean
  phoneme?: string | null
}

export interface WsMetaInfoPayload {
  subtitles?: WsSubtitleItem[]
}

type WsMessage = {
  header?: {
    namespace?: string
    name?: string
    status?: number
    status_text?: string
    task_id?: string
  }
  payload?: WsMetaInfoPayload
}

export type FetchSubtitlesOptions = {
  url?: string
  appKey: string
  token: string
  text: string
  voice?: string
  format?: 'pcm' | 'wav' | 'mp3'
  sampleRate?: 8000 | 16000 | 24000 | 48000
  enableSubtitle?: boolean
}

export async function fetchSubtitlesViaWebSocket(opts: FetchSubtitlesOptions): Promise<TimestampData[]> {
  // 使用最新文档域名：nls-gateway-cn-<region>.aliyuncs.com
  const url = opts.url ?? 'wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1'
  // 选择支持字/句级时间戳的发音人，示例：思悦(siyue)
  const voice = opts.voice ?? 'siyue'
  const format = opts.format ?? 'wav'
  const sampleRate = opts.sampleRate ?? 16000
  const enableSubtitle = opts.enableSubtitle ?? true

  return new Promise<TimestampData[]>((resolve, reject) => {
    let ws: WebSocket | null = null
    const results: TimestampData[] = []
    let closed = false

    const safeClose = () => {
      if (!closed) {
        closed = true
        try { ws?.close() } catch { /* noop */ }
      }
    }

    try {
      ws = new WebSocket(url)
    } catch (err) {
      reject(err)
      return
    }

    const sendJson = (obj: unknown) => {
      try { ws?.send(JSON.stringify(obj)) } catch { /* noop */ }
    }

    ws.onopen = () => {
      const startFrame = {
        header: {
          namespace: 'SpeechLongSynthesizer',
          name: 'StartTask',
          appkey: opts.appKey,
          token: opts.token
        },
        payload: {
          text: opts.text,
          format,
          sample_rate: sampleRate,
          voice,
          enable_subtitle: enableSubtitle ? 1 : 0
        }
      }
      sendJson(startFrame)
    }

    ws.onmessage = (evt: MessageEvent) => {
      try {
        const data: WsMessage = JSON.parse(typeof evt.data === 'string' ? evt.data : '')
        const name = data?.header?.name
        if (name === 'MetaInfo') {
          const list = data?.payload?.subtitles ?? []
          for (const item of list) {
            // 仅收集字级字幕（sentence=false）。sentence=true 是句级时间戳，可选用来划分段落
            if (typeof item?.text === 'string' && item.text.length > 0) {
              results.push({
                text: item.text,
                start: Math.max(0, item.begin_time ?? 0),
                end: Math.max(0, item.end_time ?? 0),
                phoneme: item.phoneme && item.phoneme !== 'null' ? String(item.phoneme) : undefined
              })
            }
          }
          return
        }
        if (name === 'Completed') {
          safeClose()
          resolve(results)
          return
        }
        if (name === 'Fail') {
          const msg = data?.header?.status_text || 'WS Fail'
          safeClose()
          reject(new Error(msg))
          return
        }
      } catch {
        // 非 JSON 或解析失败：忽略
      }
    }

    ws.onerror = (e) => {
      safeClose()
      reject(e instanceof Error ? e : new Error('WebSocket error'))
    }

    ws.onclose = () => {
      if (!closed) {
        closed = true
        resolve(results)
      }
    }

    // 安全超时：防止无响应悬挂
    setTimeout(() => {
      if (!closed) {
        safeClose()
        resolve(results)
      }
    }, 30000)
  })
}


